# include "World.h"

# include "Game.h"
# include "Renderer.h"

# include "Map.h"

# include "Hero.h"
# include "Quests.h"
# include "Enemy.h"
# include "PNJ.h"

World::World()
{
	myCurrentWorld = "0";

	myMap = new Map();
	myHero = new Hero();
}

World::~World()
{
	delete myMap;
	delete myHero;

	while ( !myEnemies.empty() )
	{
		delete myEnemies.back();
		myEnemies.pop_back();
	}

	while ( !myNPCs.empty() )
	{
		delete myNPCs.back();
		myNPCs.pop_back();
	}
}

void World::setCurrentWorld( const std::string& currentWorld)
{
	myCurrentWorld = currentWorld;
}

Hero* World::getHero()
{
	return myHero;
}

Map* World::getMap()
{
	return myMap;
}

Enemy* World::findEnemyName( const std::string& name)
{
	for ( unsigned int i = 0; i < myEnemies.size(); i++ )
	{
		if ( myEnemies[i]->getName() == name )
		{
			return myEnemies[i];
		}
	}

	return NULL;
}

Enemy* World::findEnemy( const Ogre::String& nodeName)
{
	for ( unsigned int i = 0; i < myEnemies.size(); i++ )
	{
		if ( myEnemies[i]->getNodeName() == nodeName )
		{
			return myEnemies[i];
		}
	}

	return NULL;
}

PNJ* World::findPNJName( const std::string& name)
{
	for ( unsigned int i = 0; i < myNPCs.size(); i++ )
	{
		if ( myNPCs[i]->getName() == name )
		{
			return myNPCs[i];
		}
	}

	return NULL;
}

PNJ* World::findPNJ( const Ogre::String& nodeName)
{
	for ( unsigned int i = 0; i < myNPCs.size(); i++ )
	{
		if ( myNPCs[i]->getNodeName() == nodeName )
		{
			return myNPCs[i];
		}
	}

	return NULL;
}

void World::init( Game* game, Renderer* renderer, AI* ai, GUI* gui)
{
	myGame = game;
	myRenderer = renderer;
	myAI = ai;
	myGUI = gui;
	
	myMap->init( renderer, "Resources/Lua/Map.lua");
	myHero->init( game, renderer, ai, this, myMap);
}

void World::createNewHero()
{
	myHero->createNewHero();
}

void World::loadWorld( const Ogre::String& nameWorld)
{	
	lua_State* stateTmp = lua_open();
	luaL_openlibs( stateTmp);
	
	if ( nameWorld == "Demo1" )
	{	
		if ( myCurrentWorld == "0" )
		{
			myHero->createNewHero();
		}

		luaL_dofile( stateTmp, "Resources/Lua/World/Demo1.lua");
	}

	else if ( nameWorld == "Demo2" )
	{
		luaL_dofile( stateTmp, "Resources/Lua/World/Demo2.lua");
	}

	lua_settop( stateTmp, 0);

	if ( myCurrentWorld != "0" )
	{
		lua_getglobal( stateTmp, myCurrentWorld.c_str());

		float posXTmp, posYTmp, posZTmp;

		lua_pushnumber( stateTmp, 1);
		lua_gettable( stateTmp, -2);
		posXTmp = lua_tonumber( stateTmp, -1);
		lua_pop( stateTmp, 1);

		lua_pushnumber( stateTmp, 2);
		lua_gettable( stateTmp, -2);
		posYTmp = lua_tonumber( stateTmp, -1);
		lua_pop( stateTmp, 1);

		lua_pushnumber( stateTmp, 3);
		lua_gettable( stateTmp, -2);
		posZTmp = lua_tonumber( stateTmp, -1);
		lua_pop( stateTmp, 1);

		myHero->setPosition( Ogre::Vector3( posXTmp, posYTmp, posZTmp));

		lua_pop( stateTmp, 1);
	}

	lua_getglobal( stateTmp, "Map");
	myMap->loadMap( lua_tostring( stateTmp, 1));
	lua_pop( stateTmp, 1);

	lua_getglobal( stateTmp, "Enemy");
				
	lua_pushnumber( stateTmp, 1);
	lua_gettable( stateTmp, -2);
	unsigned int numberTmp = lua_tonumber( stateTmp, -1);
	lua_pop( stateTmp, 1);

	for ( unsigned int i = 0; i < numberTmp; i++ )
	{
		lua_pushnumber( stateTmp, 1 + i * 5 + 1);
		lua_gettable( stateTmp, -2);

		myEnemies.push_back( new Enemy());
		myEnemies[i]->init( this, myRenderer, myAI, myGUI, lua_tostring( stateTmp, -1));
		lua_pop( stateTmp, 1);
		myEnemies[i]->setSize( 30.0f);
	
		lua_pushnumber( stateTmp, 1 + i * 5 + 2);
		lua_gettable( stateTmp, -2);
		
		myEnemies[i]->setLevel( lua_tonumber( stateTmp, -1));
		lua_pop( stateTmp, 1);

		float posXTmp, posYTmp, posZTmp;

		lua_pushnumber( stateTmp, 1 + i * 5 + 3);
		lua_gettable( stateTmp, -2);
		posXTmp = lua_tonumber( stateTmp, -1);
		lua_pop( stateTmp, 1);
	
		lua_pushnumber( stateTmp, 1 + i * 5 + 4);
		lua_gettable( stateTmp, -2);
		posYTmp = lua_tonumber( stateTmp, -1);
		lua_pop( stateTmp, 1);

		lua_pushnumber( stateTmp, 1 + i * 5 + 5);
		lua_gettable( stateTmp, -2);
		posZTmp = lua_tonumber( stateTmp, -1);
		lua_pop( stateTmp, 1);

		myEnemies[i]->setPosition( Ogre::Vector3( posXTmp, posYTmp, posZTmp));
	}

	lua_pop( stateTmp, 1);

	lua_getglobal( stateTmp, "NPC");
	
	lua_pushnumber( stateTmp, 1);
	lua_gettable( stateTmp, -2);
	numberTmp = lua_tonumber( stateTmp, -1);
	lua_pop( stateTmp, 1);

	for ( unsigned int i = 0; i < numberTmp; i++ )
	{
		lua_pushnumber( stateTmp, 1 + i * 6 + 1);
		lua_gettable( stateTmp, -2);
		std::string stringTmp = lua_tostring( stateTmp, -1);
		lua_pop( stateTmp, 1);

		lua_pushnumber( stateTmp, 1 + i * 6 + 2);
		lua_gettable( stateTmp, -2);

		myNPCs.push_back( new PNJ());
		myNPCs[i]->init( myRenderer, stringTmp, lua_tostring( stateTmp, -1));
		lua_pop( stateTmp, 1);
		myNPCs[i]->setSize( 30.0f);

		lua_pushnumber( stateTmp, 1 + i * 6 + 3);
		lua_gettable( stateTmp, -2);
		myNPCs[i]->load( lua_tostring( stateTmp, -1));
		lua_pop( stateTmp, 1);
		
		float posXTmp, posYTmp, posZTmp;

		lua_pushnumber( stateTmp, 1 + i * 6 + 4);
		lua_gettable( stateTmp, -2);
		posXTmp = lua_tonumber( stateTmp, -1);
		lua_pop( stateTmp, 1);
	
		lua_pushnumber( stateTmp, 1 + i * 6 + 5);
		lua_gettable( stateTmp, -2);
		posYTmp = lua_tonumber( stateTmp, -1);
		lua_pop( stateTmp, 1);

		lua_pushnumber( stateTmp, 1 + i * 6 + 6);
		lua_gettable( stateTmp, -2);
		posZTmp = lua_tonumber( stateTmp, -1);
		lua_pop( stateTmp, 1);

		myNPCs[i]->setPosition( Ogre::Vector3( posXTmp, posYTmp, posZTmp));
	}

	lua_close( stateTmp);

	myCurrentWorld = nameWorld;

	myHero->updateWorld();
	myHero->getQuests()->updateWorld();
}

void World::unloadWorld()
{
	myMap->unloadMap();

	while ( !myEnemies.empty() )
	{
		delete myEnemies.back();
		myEnemies.pop_back();
	}
	
	while ( !myNPCs.empty() )
	{
		delete myNPCs.back();
		myNPCs.pop_back();
	}
}

void World::unloadHero()
{
	
}

void World::oneFrame( Ogre::Real time)
{
	if ( myHero->isDead() )
	{
		Event evtTmp;

		evtTmp.message = HERO_DEATH;
		myGame->receiveEvent( evtTmp);
		return;
	}
	
	myHero->oneFrame( time);

	for ( unsigned int i = 0; i < myEnemies.size(); i++ )
	{
		myEnemies[i]->oneFrame( time);
	}

	for ( unsigned int i = 0; i < myNPCs.size(); i++ )
	{
		myNPCs[i]->oneFrame();
	}
}